package frsf.cidisi.exercise.modelo.search;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import frsf.cidisi.exercise.modelo.util.Celda;
import frsf.cidisi.exercise.modelo.util.Coordenada;
import frsf.cidisi.exercise.modelo.util.JLaberinto;
import frsf.cidisi.exercise.modelo.util.Laberinto;
import frsf.cidisi.exercise.modelo.util.Salida;
import frsf.cidisi.faia.state.EnvironmentState;

/**
 * This class represents the real world state.
 */
public class AmbienteEstado extends EnvironmentState {

	// TODO: Setup Variables
	private static int tam = 4;
	private Laberinto laberinto;
	private List<Laberinto> masNiveles;
	private List<Coordenada> listaEntradas;
	private List<Salida> listaSalidas;
	private List<Coordenada> listaLaves;
	private List< List <Coordenada> > listaEntradasPorNivel;
	private List< List <Salida> > listaSalidasPorNivel;
	private List< List <Coordenada> > listaLavesPorNivel;
	private int cantNiveles;
	private JLaberinto laberintoTable;

	public AmbienteEstado() {
		
		cantNiveles = 3;
		//Inicializo la lista de listas e inicializo las 3 listas de cada uno
		listaEntradasPorNivel = new ArrayList<List<Coordenada>>();
		listaSalidasPorNivel = new ArrayList<List<Salida>>();
		listaLavesPorNivel = new ArrayList<List<Coordenada>>();
		masNiveles = new ArrayList<Laberinto>();
		
		for(int i = 0; i < cantNiveles; i++){
			listaEntradasPorNivel.add(new ArrayList<Coordenada>());
			listaSalidasPorNivel.add(new ArrayList<Salida>());
			listaLavesPorNivel.add(new ArrayList<Coordenada>());
			masNiveles.add(new Laberinto(tam,tam));
		}

		this.initState();
		
	}

	public static void main(String args[]) {
		AmbienteEstado ae = new AmbienteEstado();
	}
	
	/**
	 * This method is used to setup the initial real world.
	 */
	@Override
	public void initState() {
		
		try {
			
			for(int k = 0; k < cantNiveles; k++){
			// Cargo el laberinto con los datos del xml
			File stocks = new File(
					"src/frsf/cidisi/exercise/modelo/resources/initialData"+k+".xml");
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
			Document doc = dBuilder.parse(stocks);
			doc.getDocumentElement().normalize();

			System.out.println("Leyendo datos del archivo del NIVEL " + (k+1) + ".");

			System.out.println("Cargando celdas...");
			NodeList celdas = doc.getElementsByTagName("celda");
			for (int i = 0; i < celdas.getLength(); i++) {
				Node nodoCelda = celdas.item(i);

				if (nodoCelda.getNodeType() == Node.ELEMENT_NODE) {
					Element element = (Element) nodoCelda;
					
					Integer x = new Integer(element.getAttribute("x"));
					Integer y = new Integer(element.getAttribute("y"));
					Boolean norte = new Boolean(
							"1".equals(element.getAttribute("norte"))  ? true : false);
					Boolean sur = new Boolean(
							"1".equals(element.getAttribute("sur")) ? true : false);
					Boolean este = new Boolean(
							"1".equals(element.getAttribute("este"))  ? true : false);
					Boolean oeste = new Boolean(
							"1".equals(element.getAttribute("oeste")) ? true : false);
					
					Coordenada posicion = new Coordenada(x, y);
					Celda celda = new Celda(norte, sur, este, oeste);
					masNiveles.get(k).addCelda(posicion, celda);

					System.out.println("Celda " + posicion + celda + " agregada al laberinto.");					
				}
			}
			
			System.out.println("Cargando entradas...");			
			NodeList entradas = doc.getElementsByTagName("entrada");
			for (int i = 0; i < entradas.getLength(); i++) {
				Node nodeEntrada = entradas.item(i);

				if (nodeEntrada.getNodeType() == Node.ELEMENT_NODE) {
					Element element = (Element) nodeEntrada;
					
					Integer x = new Integer(element.getAttribute("x"));
					Integer y = new Integer(element.getAttribute("y"));
					
					Coordenada posicion = new Coordenada(x, y);
					this.listaEntradasPorNivel.get(k).add(posicion);

					System.out.println("Entrada " + posicion + " agregada al ambiente.");	
					
				}
			}
			
			System.out.println("Cargando llaves...");
			NodeList llaves = doc.getElementsByTagName("llave");
			for (int i = 0; i < llaves.getLength(); i++) {
				Node nodeLlave = llaves.item(i);

				if (nodeLlave.getNodeType() == Node.ELEMENT_NODE) {
					Element element = (Element) nodeLlave;
					
					Integer x = new Integer(element.getAttribute("x"));
					Integer y = new Integer(element.getAttribute("y"));

					Coordenada posicion = new Coordenada(x, y);
					this.listaLavesPorNivel.get(k).add(posicion);

					System.out.println("Llave " + posicion + " agregada al ambiente.");
				}
			}
			
			System.out.println("Cargando salidas...");
			NodeList salidas = doc.getElementsByTagName("salida");
			for (int i = 0; i < salidas.getLength(); i++) {
				Node nodeSalida = salidas.item(i);

				if (nodeSalida.getNodeType() == Node.ELEMENT_NODE) {
					Element element = (Element) nodeSalida;
					
					Integer x = new Integer(element.getAttribute("x"));
					Integer y = new Integer(element.getAttribute("y"));
					Boolean cerrada = new Boolean(
							"1".equals(element.getAttribute("cerrada")) ? true : false);
					
					
					Coordenada posicion = new Coordenada(x, y);
					Salida salida = new Salida(posicion, cerrada);
					
					this.listaSalidasPorNivel.get(k).add(salida);
					
					System.out.println("Salida " + salida +" agregada al ambiente.");
				}
			}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	
	public void cambiarNivel(int nivel){
		this.laberinto = this.masNiveles.get(nivel);
		this.listaEntradas = this.listaEntradasPorNivel.get(nivel);
		this.listaSalidas = this.listaSalidasPorNivel.get(nivel);
		this.listaLaves = this.listaLavesPorNivel.get(nivel);
		
		this.laberintoTable = new JLaberinto(this, (nivel+1));

	}

	private static String getValue(String tag, Element element) {
		NodeList nodes = element.getElementsByTagName(tag).item(0)
				.getChildNodes();
		Node node = (Node) nodes.item(0);
		return node.getNodeValue();
	}
	
	private static String getAttribute(String attribute, Element element) {
		return element.getAttribute(attribute);
	}

	/**
	 * String representation of the real world state.
	 */
	@Override
	public String toString() {
		return this.getLaberinto().toString();
	}

	public Laberinto getLaberinto() {
		return laberinto;
	}

	public void setLaberinto(Laberinto laberinto) {
		this.laberinto = laberinto;
	}

	public List<Coordenada> getListaEntradas() {
		return listaEntradas;
	}

	public void setListaEntradas(List<Coordenada> listaEntradas) {
		this.listaEntradas = listaEntradas;
	}

	public List<Salida> getListaSalidas() {
		return listaSalidas;
	}

	public void setListaSalidas(List<Salida> listaSalidas) {
		this.listaSalidas = listaSalidas;
	}

	public List<Coordenada> getListaLlaves() {
		return listaLaves;
	}

	public void setListaLaves(List<Coordenada> listaLaves) {
		this.listaLaves = listaLaves;
	}

	public void addLlave(Coordenada posicion) {
		this.listaLaves.add(posicion);
	}

	public void removeLlave(Coordenada posicion) {
		this.listaLaves.remove(posicion);
	}
	
	public int getCantNiveles(){
		return this.cantNiveles;
	}
}
